home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2324 / 2324.xpi / components / SessionManagerHelperComponent.js < prev   
Text File  |  2009-11-07  |  29KB  |  731 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Michael Kraft.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2009
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *
  22.  * Alternatively, the contents of this file may be used under the terms of
  23.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  24.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25.  * in which case the provisions of the GPL or the LGPL are applicable instead
  26.  * of those above. If you wish to allow use of your version of this file only
  27.  * under the terms of either the GPL or the LGPL, and not to allow others to
  28.  * use your version of this file under the terms of the MPL, indicate your
  29.  * decision by deleting the provisions above and replace them with the notice
  30.  * and other provisions required by the GPL or the LGPL. If you do not delete
  31.  * the provisions above, a recipient may use your version of this file under
  32.  * the terms of any one of the MPL, the GPL or the LGPL.
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. const Cc = Components.classes;
  36. const Ci = Components.interfaces;
  37. const Cu = Components.utils;
  38. const report = Components.utils.reportError;
  39.  
  40. const STARTUP_PROMPT = -11;
  41. const BROWSER_STARTUP_PAGE_PREFERENCE = "browser.startup.page";
  42.  
  43. // Session Manager files
  44. const SM_BACKUP_FILE = "backup.session";
  45.  
  46. // Session Manager preferences
  47. const OLD_BROWSER_STARTUP_PAGE_PREFERENCE = "extensions.sessionmanager.old_startup_page";
  48. const SM_ALLOW_SAVE_IN_PBM_PREFERENCE = "extensions.sessionmanager.enable_saving_in_private_browsing_mode";
  49. const SM_BACKUP_SESSION_PREFERENCE = "extensions.sessionmanager.backup_session";
  50. const SM_ENCRYPT_SESSIONS_PREFERENCE = "extensions.sessionmanager.encrypt_sessions";
  51. const SM_RESUME_SESSION_PREFERENCE = "extensions.sessionmanager.resume_session";
  52. const SM_STARTUP_PREFERENCE = "extensions.sessionmanager.startup";
  53. const SM_SESSIONS_DIR_PREFERENCE = "extensions.sessionmanager.sessions_dir";
  54. const SM_SHUTDOWN_ON_LAST_WINDOW_CLOSED_PREFERENCE = "extensions.sessionmanager.shutdown_on_last_window_close";
  55.  
  56. // Session Manager app storage values
  57. const SM_ALREADY_SHUTDOWN = "sessionmanager.alreadyShutdown";
  58. const SM_COMMAND_LINE_DATA = "sessionmanager.command_line_data";
  59. const SM_SHUTDOWN_PROMPT_RESULTS = "sessionmanager.shutdown_prompt_results";
  60.  
  61. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  62.  
  63. function SessionManagerHelperComponent() {
  64.     try {
  65.         // import logger
  66.         Cu.import("resource://sessionmanager/modules/logger.js", this);
  67.     }
  68.     catch (ex) {
  69.         report(ex);
  70.     }
  71. }
  72.  
  73. SessionManagerHelperComponent.prototype = {
  74.     // registration details
  75.     classDescription: "Session Manager Helper Component",
  76.     classID:          Components.ID("{5714d620-47ce-11db-b0de-0800200c9a66}"),
  77.     contractID:       "@morac/sessionmanager-helper;1",
  78.     _xpcom_categories: [{ category: "app-startup", service: true },
  79.                         { category: "command-line-handler", entry: "sessionmanager" }],
  80.     _ignorePrefChange: false,
  81.     _warnOnQuit: null,
  82.     _sessionExt: ".session",
  83.     mAutoPrivacy: false,
  84.     mBackupState: null,
  85.     mSessionData: null,
  86.     
  87.     // interfaces supported
  88.     QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionManangerHelperComponent, Ci.nsIObserver, Ci.nsICommandLineHandler]),
  89.  
  90.     /* nsICommandLineHandler */
  91.     handle : function clh_handle(cmdLine)
  92.     {
  93.         // Find and remove the *.session command line argument and save it to a preference
  94.         let data = cmdLine.state;
  95.         let found = false;
  96.         try {
  97.             let i=0;
  98.             while (i<cmdLine.length) {
  99.                 let name = cmdLine.getArgument(i);
  100.                 if (/^.*\.session$/.test(name)) {
  101.                     // Try using absolute path first and if that doesn't work, search for the file in the session folder
  102.                     var file = null;
  103.                     try {
  104.                         file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  105.                         file.initWithPath(name);
  106.                     }
  107.                     catch (ex) {
  108.                         file = null;
  109.                     }
  110.                     if (!file) {
  111.                         file = this.getSessionDir(name);
  112.                     }
  113.                     if (file && file.exists() && file.isFile()) {
  114.                         cmdLine.removeArguments(i,i);
  115.                         found = true;
  116.                         // strip off path if specified
  117.                         data = data + "\n" + file.path;
  118.                     }
  119.                     else {
  120.                         i++;
  121.                         report("Session Manager: Command line specified session file not found or is not valid - " + name);
  122.                     }
  123.                 }
  124.                 else i++;
  125.             }
  126.         }
  127.         catch (ex) {
  128.             report("Session Manager: Command Line Error - " + ex);
  129.         }
  130.         if (found) {
  131.             try {
  132.                 let app = this.getApp();
  133.                 app.storage.set(SM_COMMAND_LINE_DATA, data);
  134.             }
  135.             catch (ex) {
  136.                 report("Session Manager: Command Line Error Setting Storage Data - " + ex);
  137.             }
  138.         }
  139.     },
  140.     
  141.     // Get FUEL or SMILE application service
  142.     getApp: function() {
  143.         let app = null;
  144.         if (Cc["@mozilla.org/fuel/application;1"]) {
  145.             app = Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication);
  146.         } else if (Cc["@mozilla.org/smile/application;1"]) {
  147.             app = Cc["@mozilla.org/smile/application;1"].getService(Ci.smileIApplication);
  148.         }
  149.         return app;
  150.     },
  151.     
  152.     log: function(aMsg, aLevel, aForce)
  153.     {
  154.         try {
  155.             if ((typeof(this.logger) == "function") && this.logger()) {
  156.                 this.logger().log(aMsg, aLevel, aForce);
  157.             }
  158.         }
  159.         catch (ex) {
  160.             report(ex);
  161.         }
  162.     },
  163.     
  164.     // observer
  165.     observe: function(aSubject, aTopic, aData)
  166.     {
  167.         let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  168.         let pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  169.         
  170.         //dump(aTopic + "\n");
  171.         this.log("SessionManagerHelperComponent observer: aTopic = " + aTopic + ", aData = " + aData + ", Subject = " + aSubject, "INFO");
  172.         switch (aTopic)
  173.         {
  174.         case "app-startup":
  175.             os.addObserver(this, "private-browsing-change-granted", false);
  176.             os.addObserver(this, "profile-after-change", false);
  177.             os.addObserver(this, "final-ui-startup", false);
  178.             os.addObserver(this, "sessionstore-state-read", false);
  179.             os.addObserver(this, "sessionstore-windows-restored", false);
  180.             os.addObserver(this, "profile-change-teardown", false);
  181.             break;
  182.         case "private-browsing-change-granted":
  183.             switch(aData) {
  184.             case "enter":
  185.                 try {
  186.                     let ss = Cc["@mozilla.org/browser/sessionstore;1"] || Cc["@mozilla.org/suite/sessionstore;1"];
  187.                     this.mBackupState = ss.getService(Ci.nsISessionStore).getBrowserState();
  188.                     this.mAutoPrivacy = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService).autoStarted;
  189.                 }
  190.                 catch(ex) { 
  191.                     report(ex); 
  192.                 }
  193.                 break;
  194.             case "exit":
  195.                 aSubject.QueryInterface(Ci.nsISupportsPRBool);
  196.                 // If browser not shutting down, clear the backup state otherwise leave it to be read by sessionmanager.js
  197.                 if (!aSubject.data) {
  198.                     this.mBackupState = null;
  199.                 }
  200.                 break;
  201.             }
  202.             break;
  203.         case "profile-after-change":
  204.             os.removeObserver(this, aTopic);
  205.             try
  206.             {
  207.                 this._restoreCache();
  208.             }
  209.             catch (ex) { report(ex); }
  210.             break;
  211.         case "final-ui-startup":
  212.             os.removeObserver(this, aTopic);
  213.             try
  214.             {
  215.                 this._handle_crash();
  216.             }
  217.             catch (ex) { report(ex); }
  218.             
  219.             // stuff to handle preference file saving
  220.             this.mTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  221.             os.addObserver(this, "quit-application-requested", false);
  222.             os.addObserver(this, "quit-application-granted", false);
  223.             // The following two notifications occur when the last browser window closes, but the application isn't actually quitting.
  224.             os.addObserver(this, "browser-lastwindow-close-requested", false);
  225.             os.addObserver(this, "browser-lastwindow-close-granted", false);
  226.             os.addObserver(this, "sessionmanager-preference-save", false);
  227.             os.addObserver(this, "sessionmanager:restore-startup-preference", false);
  228.             os.addObserver(this, "sessionmanager:ignore-preference-changes", false);
  229.             
  230.             // Observe startup preference
  231.             pb.addObserver(BROWSER_STARTUP_PAGE_PREFERENCE, this, false);
  232.             break;
  233.         case "sessionstore-windows-restored":
  234.             os.removeObserver(this, aTopic);
  235.             try 
  236.             {
  237.                 // Tell the browser windows that the initial session has been restored
  238.                 // Do this here so we don't have to add an observer to every window that opens which is
  239.                 // pointless since this only fires at browser startup. Delay a second to allow windows to load
  240.                 let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  241.                 timer.initWithCallback({
  242.                     notify:function (aTimer) { 
  243.                         Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).notifyObservers(null, "sessionmanager:initial-windows-restored", null); 
  244.                     }
  245.                 }, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
  246.             }
  247.             catch (ex) { report(ex); }
  248.             break;
  249.         case "sessionstore-state-read":
  250.             os.removeObserver(this, aTopic);
  251.             try 
  252.             {
  253.                 this._check_for_crash(aSubject);
  254.             }
  255.             catch (ex) { report(ex); }
  256.             break;
  257.         case "sessionmanager-preference-save":
  258.             // Save preference file after one 1/4 second to delay in case another preference changes at same time as first
  259.             this.mTimer.cancel();
  260.             this.mTimer.initWithCallback({
  261.                 notify:function (aTimer) { Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).savePrefFile(null); }
  262.             }, 250, Ci.nsITimer.TYPE_ONE_SHOT);
  263.             break;
  264.         case "sessionmanager:restore-startup-preference":
  265.             os.removeObserver(this, aTopic);
  266.             this._ignorePrefChange = true;
  267.             try 
  268.             {
  269.                 // Restore browser startup preference if Session Manager previously saved it, otherwise backup current browser startup preference
  270.                 if (pb.prefHasUserValue(OLD_BROWSER_STARTUP_PAGE_PREFERENCE)) {
  271.                     pb.setIntPref(BROWSER_STARTUP_PAGE_PREFERENCE, pb.getIntPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE));
  272.                 }
  273.                 else {
  274.                     pb.setIntPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE, pb.getIntPref(BROWSER_STARTUP_PAGE_PREFERENCE));
  275.                 }
  276.             }
  277.             catch (ex) { report(ex); }
  278.             this._ignorePrefChange = false;
  279.             break;
  280.         case "sessionmanager:ignore-preference-changes":
  281.             this._ignorePrefChange = (aData == "true");
  282.             break;
  283.         // quitting or closing last browser window
  284.         case "browser-lastwindow-close-requested":
  285.         case "quit-application-requested":
  286.             // If quit already canceled, just return
  287.             if (aSubject.QueryInterface(Ci.nsISupportsPRBool) && aSubject.data) return;
  288.  
  289.             // If private browsing mode don't allow saving unless overridding
  290.             try {
  291.                 let inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService).privateBrowsingEnabled;
  292.                 if (inPrivateBrowsing) {
  293.                     if (!pb.getBoolPref(SM_ALLOW_SAVE_IN_PBM_PREFERENCE) || !pb.getBoolPref(SM_ENCRYPT_SESSIONS_PREFERENCE)) {
  294.                         return;
  295.                     }
  296.                 }
  297.             } catch(ex) {}
  298.             
  299.             let backup = pb.getIntPref(SM_BACKUP_SESSION_PREFERENCE);
  300.             let resume_current = (pb.getIntPref(BROWSER_STARTUP_PAGE_PREFERENCE) == 3) || pb.getBoolPref("browser.sessionstore.resume_session_once");
  301.  
  302.             // If not restarting and set to prompt, disable FF's quit prompt
  303.             if ((aData != "restart") && (backup == 2)) {
  304.                 let window = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
  305.                 if ((backup == 2) && ((aTopic == "quit-application-requested") || pb.getBoolPref(SM_SHUTDOWN_ON_LAST_WINDOW_CLOSED_PREFERENCE))) {
  306.  
  307.                     // Do session prompt here and then save the info in an Application Storage variable for use in
  308.                     // the shutdown procsesing in sessionmanager.js
  309.                     let watcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
  310.                     let app = this.getApp();
  311.                     // if didn't already shut down
  312.                     if (app && !app.storage.get(SM_ALREADY_SHUTDOWN, false)) {
  313.                         let bundle = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService).createBundle("chrome://sessionmanager/locale/sessionmanager.properties");
  314.  
  315.                         // Manually construct the prompt window because the promptService doesn't allow 4 button prompts
  316.                         let params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  317.                         params.SetInt(0, 1);                                                 // Set default to cancel
  318.                         params.SetString(0, bundle.GetStringFromName("preserve_session"));    // dialog text
  319.                         params.SetString(1, bundle.GetStringFromName("prompt_not_again"));    // checkbox text
  320.                         params.SetString(12, bundle.GetStringFromName("sessionManager"));    // title
  321.                         
  322.                         // buttons are tricky because they don't display in order
  323.                         // if there are 4 buttons they display as 11, 8, 10, 9
  324.                         // if there are 3 buttons they display as 8, 10, 9
  325.                         // A button always returns it's string number - 8, eg: 10 returns 2.
  326.                         // So we need to tweak things when displaying 3 or 4 buttons.
  327.                         
  328.                         if (resume_current) {
  329.                             params.SetInt(2, 3);                                                // Display 3 buttons
  330.                             params.SetString(8, bundle.GetStringFromName("save_quit"));            // first button text (returns 0)
  331.                             params.SetString(10, bundle.GetStringFromName("quit"));                // second button text (returns 2)
  332.                             params.SetString(9, bundle.GetStringFromName("cancel"));            // third button text (returns 1)
  333.                         }
  334.                         else {
  335.                             params.SetInt(2, 4);                                                // Display 4 buttons
  336.                             params.SetString(11, bundle.GetStringFromName("save_quit"));        // first button text (returns 3)
  337.                             params.SetString(8, bundle.GetStringFromName("quit"));                // second button text (returns 0)
  338.                             params.SetString(10, bundle.GetStringFromName("save_and_restore"));    // third button text (returns 2)
  339.                             params.SetString(9, bundle.GetStringFromName("cancel"));            // fourth button text (returns 1)
  340.                         }
  341.                         
  342.                         watcher.openWindow(window, "chrome://global/content/commonDialog.xul", "_blank", "centerscreen,chrome,modal,titlebar", params);
  343.                         let results = params.GetInt(0);
  344.                             
  345.                         // If cancel pressed, cancel shutdown and return;
  346.                         if (results == 1) {
  347.                             aSubject.QueryInterface(Ci.nsISupportsPRBool);
  348.                             aSubject.data = true;
  349.                             return;
  350.                         }
  351.                         
  352.                         // At this point the results value doesn't match what the
  353.                         // backupCurrentSession function in sessionmanager.js expects which is
  354.                         // the Save & Quit to be 0, Quit to be 1 and Save & Restore to be 2, so tweak the values here.
  355.                         switch (results) {
  356.                             // Save & Quit when four buttons displayed
  357.                             case 3:
  358.                                 results = 0;
  359.                                 break;
  360.                             // Quit (4 buttons) or Save & Quit (3 buttons)
  361.                             case 0:
  362.                                 results = resume_current ? 0 : 1;
  363.                                 break;
  364.                             case 2:
  365.                                 results = resume_current ? 1 : 2;
  366.                         }
  367.                         
  368.                         // If checkbox checked
  369.                         if (params.GetInt(1))
  370.                         {
  371.                             if (results == 2) {
  372.                                 let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
  373.                                 str.data = SM_BACKUP_FILE;
  374.                                 pb.setComplexValue(SM_RESUME_SESSION_PREFERENCE, Ci.nsISupportsString, str);
  375.                                 pb.setIntPref(SM_STARTUP_PREFERENCE, 2)
  376.                             }
  377.                             pb.setIntPref(SM_BACKUP_SESSION_PREFERENCE, (results == 1)?0:1);
  378.                         }
  379.                                 
  380.                         app.storage.set(SM_SHUTDOWN_PROMPT_RESULTS, results);
  381.                         
  382.                         // Disable prompt in browser
  383.                         if (pb.getPrefType("browser.warnOnQuit") == pb.PREF_BOOL) {
  384.                             if (typeof(this._warnOnQuit) != "boolean") {
  385.                                 this._warnOnQuit = pb.getBoolPref("browser.warnOnQuit");
  386.                             }
  387.                             pb.setBoolPref("browser.warnOnQuit", false);
  388.                         }
  389.                         // Disable prompt in tab mix plus if it's running
  390.                         if (pb.getPrefType("browser.tabs.warnOnClose") == pb.PREF_BOOL) {
  391.                             if (typeof(this._warnOnClose) != "boolean") {
  392.                                 this._warnOnClose = pb.getBoolPref("browser.tabs.warnOnClose");
  393.                             }
  394.                             pb.setBoolPref("browser.tabs.warnOnClose", false);
  395.                         }
  396.                         if (pb.getPrefType("extensions.tabmix.protectedtabs.warnOnClose") == pb.PREF_BOOL) {
  397.                             if (typeof(this._TMP_protectedtabs_warnOnClose) != "boolean") {
  398.                                 this._TMP_protectedtabs_warnOnClose = pb.getBoolPref("extensions.tabmix.protectedtabs.warnOnClose");
  399.                             }
  400.                             pb.setBoolPref("extensions.tabmix.protectedtabs.warnOnClose", false);
  401.                         }
  402.                     }
  403.                 }
  404.             }
  405.             break;
  406.         case "browser-lastwindow-close-granted":
  407.             if (typeof(this._warnOnQuit) == "boolean") {
  408.                 pb.setBoolPref("browser.warnOnQuit", this._warnOnQuit);
  409.             }
  410.             if (typeof(this._warnOnClose) == "boolean") {
  411.                 pb.setBoolPref("browser.tabs.warnOnClose", this._warnOnClose);
  412.             }
  413.             if (typeof(this._TMP_protectedtabs_warnOnClose) == "boolean") {
  414.                 pb.setBoolPref("extensions.tabmix.protectedtabs.warnOnClose", this._TMP_protectedtabs_warnOnClose);
  415.             }
  416.             break;
  417.         case "quit-application-granted":
  418.             if (typeof(this._warnOnQuit) == "boolean") {
  419.                 pb.setBoolPref("browser.warnOnQuit", this._warnOnQuit);
  420.             }
  421.             if (typeof(this._warnOnClose) == "boolean") {
  422.                 pb.setBoolPref("browser.tabs.warnOnClose", this._warnOnClose);
  423.             }
  424.             if (typeof(this._TMP_protectedtabs_warnOnClose) == "boolean") {
  425.                 pb.setBoolPref("extensions.tabmix.protectedtabs.warnOnClose", this._TMP_protectedtabs_warnOnClose);
  426.             }
  427.             os.removeObserver(this, "sessionmanager-preference-save");
  428.             os.removeObserver(this, "sessionmanager:ignore-preference-changes");
  429.             os.removeObserver(this, "quit-application-requested");
  430.             os.removeObserver(this, "browser-lastwindow-close-requested");
  431.             os.removeObserver(this, "browser-lastwindow-close-granted");
  432.             os.removeObserver(this, aTopic);
  433.             
  434.             // Remove preference observer
  435.             pb.removeObserver(BROWSER_STARTUP_PAGE_PREFERENCE, this);
  436.             break;
  437.         case "profile-change-teardown":
  438.             let page = pb.getIntPref(BROWSER_STARTUP_PAGE_PREFERENCE);
  439.             // If Session Manager is handling startup, save the current startup preference and then set it to home page
  440.             // otherwise clear the saved startup preference
  441.             if ((page == 3) && pb.getIntPref(SM_STARTUP_PREFERENCE)) {
  442.                 pb.setIntPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE, page);
  443.                 pb.clearUserPref(BROWSER_STARTUP_PAGE_PREFERENCE);
  444.             }
  445.             else if (pb.prefHasUserValue(OLD_BROWSER_STARTUP_PAGE_PREFERENCE)) {
  446.                 pb.clearUserPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE);
  447.             }
  448.             break;
  449.         case "nsPref:changed":
  450.             switch(aData) 
  451.             {
  452.                 case BROWSER_STARTUP_PAGE_PREFERENCE:
  453.                     // Handle case where user changes browser startup preference
  454.                     if (!this._ignorePrefChange) this._synchStartup();
  455.                     break;
  456.             }
  457.             break;
  458.         }
  459.     },
  460.  
  461.     /* ........ public methods ............... */
  462.  
  463.     // this will save the passed in session data into the mSessionData variable
  464.     setSessionData: function sm_setSessionData(aState) 
  465.     {
  466.         this.mSessionData = aState;
  467.     },
  468.  
  469.     /* ........ private methods .............. */
  470.  
  471.     // this will remove certain preferences in the case where user turned off crash recovery in the browser and browser is not restarting
  472.     _handle_crash: function sm_handle_crash()
  473.     {
  474.         let prefroot = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  475.         let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"] || Cc["@mozilla.org/suite/sessionstartup;1"];
  476.         if (sessionStartup) sessionStartup = sessionStartup.getService(Ci.nsISessionStartup);
  477.         // This will only be set to true, if crash recovery is turned off and browser is not restarting
  478.         let no_remove = (sessionStartup && sessionStartup.sessionType && (sessionStartup.sessionType != Ci.nsISessionStartup.NO_SESSION)) ||
  479.                          prefroot.getBoolPref("browser.sessionstore.resume_session_once") || 
  480.                          prefroot.getBoolPref("browser.sessionstore.resume_from_crash");
  481.  
  482.         //dump("no_remove = " + resuming + "\n");
  483.         //report("no_remove = " + resuming);
  484.         // Unless browser is restarting, always delete the following preferences if crash recovery is disabled in case the browser crashes
  485.         // otherwise bad things can happen
  486.         if (!no_remove)
  487.         {
  488.             //dump("SessionManager: Removing preferences\n");
  489.             prefroot.deleteBranch("extensions.sessionmanager._autosave_values");
  490.             prefroot.deleteBranch("extensions.sessionmanager._recovering");
  491.             prefroot.deleteBranch("extensions.sessionmanager._encrypt_file");
  492.             prefroot.deleteBranch("extensions.sessionmanager._chose_tabs");
  493.         }
  494.     },
  495.     
  496.     // This will check to see if there was a crash and if so put up the crash prompt 
  497.     // to allow the user to choose a session to restore.  This is only called for Firefox 3.5 and up and SeaMonkey 2.0 and up
  498.     _check_for_crash: function sm_check_for_crash(aStateDataString)
  499.     {
  500.         let initialState;
  501.         try {
  502.             // parse the session state into JS objects
  503.             initialState = this.JSON_decode(aStateDataString.QueryInterface(Ci.nsISupportsString).data);
  504.         }
  505.         catch (ex) { 
  506.             report("The startup session file is invalid: " + ex); 
  507.             return;
  508.         } 
  509.     
  510.         let lastSessionCrashed =
  511.             initialState && initialState.session && initialState.session.state &&
  512.             initialState.session.state == "running";
  513.         
  514.         //report("Last Crashed = " + lastSessionCrashed);
  515.         if (lastSessionCrashed) {
  516.             let params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  517.             // default to recovering
  518.             params.SetInt(0, 0);
  519.             Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher).
  520.                 openWindow(null, "chrome://sessionmanager/content/restore_prompt.xul", "_blank", "chrome,modal,centerscreen,titlebar", params);
  521.             if (params.GetInt(0) == 1) aStateDataString.QueryInterface(Ci.nsISupportsString).data = "";
  522.             else if (initialState.session) {
  523.                 // don't prompt for tabs if checkbox not checked
  524.                 delete(initialState.session.lastUpdate);
  525.                 delete(initialState.session.recentCrashes);
  526.                 aStateDataString.QueryInterface(Ci.nsISupportsString).data = this.JSON_encode(initialState);
  527.             }
  528.         }
  529.         initialState = null;
  530.     },
  531.  
  532.     // code adapted from Danil Ivanov's "Cache Fixer" extension
  533.     _restoreCache: function sm_restoreCache()
  534.     {
  535.         let cache = null;
  536.         try 
  537.         {
  538.             let prefroot = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  539.             let disabled = prefroot.getBoolPref("extensions.sessionmanager.disable_cache_fixer");
  540.             if (disabled)
  541.             {
  542.                 let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
  543.                   consoleService.logStringMessage("SessionManager: Cache Fixer disabled");
  544.                 return;
  545.             }
  546.             let pd_path = prefroot.getComplexValue("browser.cache.disk.parent_directory",Ci.nsISupportsString).data;
  547.             cache = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  548.             cache.initWithPath(pd_path);
  549.         }
  550.         catch (ex) {}
  551.         
  552.         if (!cache) cache = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfLD", Ci.nsILocalFile);
  553.         cache.append("Cache");
  554.         cache.append("_CACHE_MAP_");
  555.         if (!cache.exists())
  556.         {
  557.             return;
  558.         }
  559.         
  560.         let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
  561.         stream.init(cache, 0x01, 0, 0); // PR_RDONLY
  562.         let input = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
  563.         input.setInputStream(stream);
  564.         let content = input.readByteArray(input.available());
  565.         input.close();
  566.         
  567.         if (content[15] != 1)
  568.         {
  569.             return;
  570.         }
  571.         content[15] = 0;
  572.         
  573.         stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
  574.         stream.init(cache, 0x02 | 0x20, 0600, 0); // PR_WRONLY | PR_TRUNCATE
  575.         let output = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
  576.         output.setOutputStream(stream);
  577.         output.writeByteArray(content, content.length);
  578.         output.flush();
  579.         output.close();
  580.     },
  581.  
  582.     // Make sure that the browser and Session Manager are on the same page with regards to the startup preferences
  583.     _synchStartup: function sm_synchStartup()
  584.     {
  585.         let pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  586.         let browser_startup = pb.getIntPref(BROWSER_STARTUP_PAGE_PREFERENCE);
  587.         let sm_startup = pb.getIntPref(SM_STARTUP_PREFERENCE);
  588.         //dump("page:" + browser_startup + ", startup:" + sm_startup + "\n");
  589.  
  590.         // Ignore any preference changes made in this function
  591.         this._ignorePrefChange = true;
  592.         
  593.         // If browser handling startup, disable Session Manager startup and backup startup page
  594.         // otherwise set Session Manager to handle startup and restore browser startup setting
  595.         if (browser_startup > STARTUP_PROMPT) {
  596.             pb.setIntPref(SM_STARTUP_PREFERENCE, 0);
  597.             pb.setIntPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE, browser_startup);
  598.         }
  599.         else {
  600.             pb.setIntPref(SM_STARTUP_PREFERENCE, (browser_startup == STARTUP_PROMPT) ? 1 : 2);
  601.             pb.setIntPref(BROWSER_STARTUP_PAGE_PREFERENCE, pb.getIntPref(OLD_BROWSER_STARTUP_PAGE_PREFERENCE));
  602.         }
  603.  
  604.         // Resume listening to preference changes
  605.         this._ignorePrefChange = false;
  606.     },
  607.  
  608.     // Get the profile dir
  609.     getProfileFile: function getProfileFile(aFileName)
  610.     {
  611.         let file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsILocalFile).clone();
  612.         file.append(aFileName);
  613.         return file;
  614.     },
  615.     
  616.     // Get the user specific sessions directory
  617.     getUserDir: function getUserDir(aFileName)
  618.     {
  619.         let dir = null;
  620.         let dirname = null;
  621.  
  622.         try {
  623.             let pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  624.             dirname = pb.getComplexValue(SM_SESSIONS_DIR_PREFERENCE,Ci.nsISupportsString).data;
  625.             if (dirname) {
  626.                 let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  627.                 dir.initWithPath(dirname);
  628.                 if (dir.isDirectory && dir.isWritable()) {
  629.                     dir.append(aFileName);
  630.                 }
  631.                 else {
  632.                     dir = null;
  633.                 }
  634.             }
  635.         } catch (ex) {
  636.             dir = null;
  637.         } finally {
  638.             return dir;
  639.         }
  640.     },
  641.  
  642.     // Get the sessions dir
  643.     getSessionDir: function getSessionDir(aFileName, aUnique)
  644.     {
  645.         // allow overriding of location of sessions directory
  646.         let dir = this.getUserDir("sessions");
  647.             
  648.         // use default is not specified or not a writable directory
  649.         if (dir == null) {
  650.             dir = this.getProfileFile("sessions");
  651.         }
  652.         if (!dir.exists())
  653.         {
  654.             try {
  655.                 dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
  656.             }
  657.             catch (ex) {
  658.                 report("Session Manager: File Error - " + ex);
  659.                 return null;
  660.             }
  661.         }
  662.         if (aFileName)
  663.         {
  664.             dir.append(aFileName);
  665.             if (aUnique)
  666.             {
  667.                 let postfix = 1, ext = "";
  668.                 if (aFileName.slice(-this._sessionExt.length) == this._sessionExt)
  669.                 {
  670.                     aFileName = aFileName.slice(0, -this._sessionExt.length);
  671.                     ext = this._sessionExt;
  672.                 }
  673.                 while (dir.exists())
  674.                 {
  675.                     dir = dir.parent;
  676.                     dir.append(aFileName + "-" + (++postfix) + ext);
  677.                 }
  678.             }
  679.         }
  680.         return dir.QueryInterface(Ci.nsILocalFile);
  681.     },
  682.     
  683.     // Decode JSON string to javascript object
  684.     JSON_decode: function sm_JSON_decode(aStr) {
  685.         let jsObject = { windows: [{ tabs: [{ entries:[] }], selected:1, _closedTabs:[] }], _JSON_decode_failed:true };
  686.         try {
  687.             let hasParens = ((aStr[0] == '(') && aStr[aStr.length-1] == ')');
  688.         
  689.             // JSON can't parse when string is wrapped in parenthesis
  690.             if (hasParens) {
  691.                 aStr = aStr.substring(1, aStr.length - 1);
  692.             }
  693.         
  694.             // Session Manager 0.6.3.5 and older had been saving non-JSON compiant data so try to use evalInSandbox if JSON parse fails
  695.             try {
  696.                 jsObject = JSON.parse(aStr);
  697.             }
  698.             catch (ex) {
  699.                 if (/[\u2028\u2029]/.test(aStr)) {
  700.                     aStr = aStr.replace(/[\u2028\u2029]/g, function($0) {"\\u" + $0.charCodeAt(0).toString(16)});
  701.                 }
  702.                 jsObject = Cu.evalInSandbox("(" + aStr + ")", new Cu.Sandbox("about:blank"));
  703.             }
  704.         }
  705.         catch(ex) {
  706.             report("SessionManager: " + ex);
  707.         }
  708.         return jsObject;
  709.     },
  710.     
  711.     // Encode javascript object to JSON string - use JSON if built-in.
  712.     JSON_encode: function sm_JSON_encode(aObj) {
  713.         let jsString = null;
  714.         try {
  715.             jsString = JSON.stringify(aObj);
  716.             // Workaround for Firefox bug 485563
  717.             if (/[\u2028\u2029]/.test(jsString)) {
  718.                 jsString = jsString.replace(/[\u2028\u2029]/g, function($0) {"\\u" + $0.charCodeAt(0).toString(16)});
  719.             }
  720.         }
  721.         catch(ex) {
  722.             report("SessionManager: " + ex);
  723.         }
  724.         return jsString;
  725.     },
  726. };
  727.  
  728. // Register Component
  729. function NSGetModule(compMgr, fileSpec) {
  730.   return XPCOMUtils.generateModule([SessionManagerHelperComponent]);
  731. }